package middleware

import (
	"bytes"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

type respBodyWriter struct {
	gin.ResponseWriter
	body *bytes.Buffer
}

func (w respBodyWriter) Write(b []byte) (int, error) {
	w.body.Write(b)
	return w.ResponseWriter.Write(b)
}

// GinLogger 日志中间件
func GinLogger(logger *zap.SugaredLogger) gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()
		rbw := &respBodyWriter{
			body:           bytes.NewBufferString(""),
			ResponseWriter: c.Writer,
		}
		c.Writer = rbw

		body, err := c.GetRawData()
		if err == nil && len(body) != 0 {
			c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
		}
		c.Next()

		latency := time.Since(start)

		// 状态码小于400, 则不用记录 response
		if c.Writer.Status() <= http.StatusBadRequest {
			if len(body) == 0 {
				logger.Infof("Request(%s,%3d,%v) %s", c.Request.Method, c.Writer.Status(), latency, c.Request.URL)
				return
			}
			logger.Infof("Request(%s,%3d,%v) %s, [Body]: %v",
				c.Request.Method, c.Writer.Status(), latency, c.Request.URL, body)
			return
		}

		logger.Errorf("Request(%s,%3d,%v) %s, [Header]: %s,  [Body]: %s, [Response]: %s",
			c.Request.Method, c.Writer.Status(), latency, c.Request.URL,
			formatHeader(c.Request.Header), body, rbw.body.String())
	}
}

func formatHeader(header http.Header) string {
	buf := bytes.NewBuffer(nil)
	for k, v := range header {
		buf.WriteString(k + ":" + strings.Join(v, ";") + " ")
	}
	return buf.String()
}
